package com.quectel.business.common.alarm;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.quectel.business.common.sms.SmsBusiness;
import com.quectel.business.common.websocket.WebSocketComponent;
import com.quectel.business.common.websocket.send.SendMsgType;
import com.quectel.constant.core.alarm.AlarmConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysConfigKeyConstants;
import com.quectel.core.module.alarm.dto.*;
import com.quectel.core.module.alarm.dto.resp.EventGenerateResponse;
import com.quectel.core.module.alarm.service.*;
import com.quectel.core.module.device.dto.DeviceCategoryDto;
import com.quectel.core.module.device.dto.DeviceCurrentAlarmDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.dto.DeviceTypeDto;
import com.quectel.core.module.device.dto.mongo.MongoDeviceAlarmLogDto;
import com.quectel.core.module.device.dto.mongo.MongoDeviceDataLogDto;
import com.quectel.core.module.device.service.DeviceCurrentAlarmService;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.device.service.mongo.MongoDeviceService;
import com.quectel.sys.module.sys.dto.SysUserDto;
import com.quectel.sys.module.sys.service.SysConfigService;
import com.quectel.sys.module.sys.service.SysUserService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.http.HttpRestUtils;
import com.quectel.util.redis.RedisUtils;
import com.quectel.util.security.RandomHeaderSignUtils;
import com.quectel.util.thread.ThreadPoolUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * 数据处理中心 数据接收解析完 自动处理 告警、事件、 工单等信息
 *
 * @author caolu
 * @email louis.cao@quectel.com
 */
@Component
@Slf4j
public class DataProcessingComponent implements DisposableBean {
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private DeviceCurrentAlarmService deviceCurrentAlarmService;
    @DubboReference
    private AlarmRuleService alarmRuleService;
    @DubboReference
    private AlarmEventConfigService alarmEventConfigService;
    @DubboReference
    private AlarmEventPushUserService alarmEventPushUserService;
    @DubboReference
    private AlarmEventRecordService alarmEventRecordService;
    @DubboReference
    private AlarmLinkageRuleService alarmLinkageRuleService;
    @DubboReference
    private MongoDeviceService mongoDeviceService;
    @DubboReference
    private SysConfigService sysConfigService;
    @DubboReference
    private SysUserService sysUserService;
    @Autowired
    private SmsBusiness smsBusiness;
    @Autowired
    private WebSocketComponent webSocketComponent;

    private static final HttpRestUtils HTTP_REST_UTILS = HttpRestUtils.getDefaultInstance();


    private static final String DEVICE_ALARM_LOCK = "DEVICE_ALARM_LOCK";


    /**
     * 处理线程
     */
    private static final ThreadPoolExecutor DATA_PROCESSING_THREAD_POOL = ThreadPoolUtils.createCommonIOBoundPool("data_processing_thread_pool_");

    @Override
    public void destroy() throws Exception {
        ThreadPoolUtils.shutdown(DATA_PROCESSING_THREAD_POOL);
    }

    /**
     * 数据处理中心
     *
     * @param deviceDto    接收数据的设备
     * @param originalData 原始数据
     * @param parsedData   解析后的数据
     */
    public void handleData(DeviceDto deviceDto, String originalData, Map<String, Object> parsedData) {
        if (deviceDto == null) {
            return;
        }

        log.info("设备:{} imei为{}开始对数据进行分析处理", deviceDto.getName(), deviceDto.getImei());

        long t1 = System.currentTimeMillis();

        handleOnlineStatus(deviceDto, parsedData);
        log.info("处理在离线状态变更结束，已耗时{}ms", System.currentTimeMillis() - t1);


        //1推送数据到mongodb 可以异步 当前已开启异步
        pushDataToMongoDB(deviceDto, originalData, parsedData);
        log.info("数据持久化到mongodb结束,已耗时:{}ms", System.currentTimeMillis() - t1);

        //2处理告警 必须同步处理
        HandleAlarmResp handleAlarmResp = handleAlarm(deviceDto, originalData, parsedData);
        log.info("告警结束，已耗时{}ms", System.currentTimeMillis() - t1);

        //3处理事件和工单 异步处理
        DATA_PROCESSING_THREAD_POOL.submit(() -> {
            handleAlarmEventAndWorkOrder(deviceDto, handleAlarmResp);
        });

        log.info("处理事件和工单结束，已耗时{}ms", System.currentTimeMillis() - t1);


    }

    /**
     * 根据定时任务或设备上报数据进行在离线状态变更
     *
     * @param deviceDto
     * @param parsedData
     */
    private void handleOnlineStatus(DeviceDto deviceDto, Map<String, Object> parsedData) {
        if (SystemConstants.ABNORMAL.equals(parsedData.get(AlarmConstants.DEVICE_OFFLINE_FLAG))) {
            DeviceDto newlyDto = new DeviceDto();
            newlyDto.setId(deviceDto.getId());
            newlyDto.setOnlineStatus(SystemConstants.ABNORMAL);
            deviceService.updateById(newlyDto);
        } else {
            // 消除离线告警
            parsedData.put(AlarmConstants.DEVICE_OFFLINE_FLAG, SystemConstants.NORMAL);
            DeviceDto newlyDto = new DeviceDto();
            newlyDto.setId(deviceDto.getId());
            newlyDto.setOnlineStatus(SystemConstants.NORMAL);
            newlyDto.setLastHeartbeat(new Date());
            deviceService.updateById(newlyDto);
        }
    }


    /**
     * 根据本次上报的数据进行数据的事件记录和工单记录的生成
     *
     * @param handleAlarmResp 处理告警后返回的信息
     */
    public void handleAlarmEventAndWorkOrder(DeviceDto deviceDto, HandleAlarmResp handleAlarmResp) {

        if (SystemConstants.NO.equals(deviceDto.getEventSwitch())) {
            log.info("设备事件关闭,不处理事件");
            return;
        }
        if (handleAlarmResp == null) {
            log.info("设备告警没有返回所需数据,不处理事件");
            return;
        }


        List<AlarmEventConfigDto> eventConfigs = alarmEventConfigService.selectCacheByDeviceAttr(deviceDto.getTenantId(), deviceDto.getVillageId(), deviceDto.getDeviceTypeId());

        List<AlarmEventConfigDto> orConfigs =
                eventConfigs.stream().filter(v -> AlarmConstants.ALARM_EVENT_CONFIG_TRIGGER_OR.equals(v.getTriggerType())).collect(Collectors.toList());
        List<AlarmEventConfigDto> andConfigs =
                eventConfigs.stream().filter(v -> AlarmConstants.ALARM_EVENT_CONFIG_TRIGGER_AND.equals(v.getTriggerType())).collect(Collectors.toList());

        for (HandAlarmRuleInfo handAlarmRuleInfo : handleAlarmResp.getRealAlarmOrRecoverList()) {
            if (AlarmConstants.ALARM_YES.equals(handAlarmRuleInfo.getAlarmConformLevel())) {
                // 1 对于或规则的事件  有一个当前告警就产生新的事件
                for (AlarmEventConfigDto orConfig : orConfigs) {
                    if (StringUtils.isNotBlank(orConfig.getAlarmRuleIds())) {
                        if (
                                JacksonUtils.parseArray(orConfig.getAlarmRuleIds(), Long.class).contains(handAlarmRuleInfo.getAlarmRuleDto().getId())
                        ) {
                            //开始生成事件记录 包括工单的保存 需要在同一事务上
                            AlarmEventRecordDto alarmEventRecordDto = new AlarmEventRecordDto();
                            alarmEventRecordDto.setTenantId(deviceDto.getTenantId());
                            alarmEventRecordDto.setVillageId(deviceDto.getVillageId());
                            alarmEventRecordDto.setBuildingId(deviceDto.getBuildingId());
                            alarmEventRecordDto.setDeviceCategoryId(deviceDto.getDeviceCategoryId());
                            alarmEventRecordDto.setDeviceTypeId(deviceDto.getDeviceTypeId());
                            alarmEventRecordDto.setDeviceId(deviceDto.getId());
                            alarmEventRecordDto.setImei(deviceDto.getImei());
                            alarmEventRecordDto.setEventConfigId(orConfig.getTenantId());
                            alarmEventRecordDto.setName(orConfig.getName());
                            alarmEventRecordDto.setEventDesc(orConfig.getEventDesc());
                            alarmEventRecordDto.setStatus(AlarmConstants.ALARM_EVENT_RECORD_HANDLING);
                            alarmEventRecordDto.setEventTime(new Date());

                            alarmEventRecordDto.setDeviceDto(deviceDto);

                            orConfig.setLinkageUrl(sysConfigService.getConfigValueByKey(SysConfigKeyConstants.GATEWAY_INNER_BASE_URL) + SystemConstants.ApiPath.CMS_PATH + "/alarmLinkageCallback");

                            alarmEventRecordDto.setAlarmEventConfigDto(orConfig);

                            if (SystemConstants.YES.equals(orConfig.getIsAutoGenerateWorkOrder())) {
                                SysUserDto sysUserDto = sysUserService.selectCacheById(orConfig.getWorkOrderHandlerId());
                                if (sysUserDto != null) {
                                    orConfig.setWorkOrderHandlerUsername(sysUserDto.getUsername());
                                    orConfig.setWorkOrderHandlerMobile(sysUserDto.getMobile());
                                    orConfig.setWorkOrderHandlerEmail(sysUserDto.getEmail());
                                }
                            }
                            EventGenerateResponse response = alarmEventRecordService.generateEventRecord(alarmEventRecordDto);
                            if (response.isNeedPush()) {
                                pushMsg(alarmEventRecordDto);
                            }
                            if (response.isNeedLinkDevice()) {
                                linkDevice(alarmEventRecordDto);
                            }
                        }
                    }
                }

            } else {
                // 1 对于且规则的事件  有一个不满足就恢复
                for (AlarmEventConfigDto andConfig : andConfigs) {
                    if (StringUtils.isNotBlank(andConfig.getAlarmRuleIds())) {
                        if (JacksonUtils.parseArray(andConfig.getAlarmRuleIds(), Long.class).contains(handAlarmRuleInfo.getAlarmRuleDto().getId())) {
                            //恢复
                            alarmEventRecordService.autoCloseEventByEventConfigId(deviceDto.getId(), andConfig.getId());
                        }

                    }
                }
            }
        }
        if ((orConfigs != null && orConfigs.size() > 0) || (andConfigs != null && andConfigs.size() > 0)) {

            List<Long> dbCurrentAlarmRules = handleAlarmResp.getDeviceCurrentAlarms().stream().map(v -> v.getRuleId()).collect(Collectors.toList());

            if (orConfigs != null && orConfigs.size() > 0) {
                //3基于数据库 都不存在 对or进行恢复
                for (int i = 0; i < orConfigs.size(); i++) {
                    AlarmEventConfigDto orConfig = orConfigs.get(0);

                    if (dbCurrentAlarmRules.size() <= 0) {
                        //数据库都不存在告警 直接恢复
                        alarmEventRecordService.autoCloseEventByEventConfigId(deviceDto.getId(), orConfig.getId());
                    } else {
                        if (orConfig.getAlarmRuleIds() != null) {
                            List<Long> ruleIds = JacksonUtils.parseArray(orConfig.getAlarmRuleIds(), Long.class);
                            int j = 0;
                            for (j = 0; j < ruleIds.size(); j++) {
                                if (dbCurrentAlarmRules.contains(ruleIds.get(j))) {
                                    //数据库还存在或 存在一个就不能恢复
                                    break;
                                }
                            }
                            if (j >= ruleIds.size()) {
                                //数据库都不存在告警 直接恢复
                                alarmEventRecordService.autoCloseEventByEventConfigId(deviceDto.getId(), orConfig.getId());
                            }
                        }
                    }
                }
            }
            if (andConfigs != null && andConfigs.size() > 0) {
                if (dbCurrentAlarmRules.size() <= 0) {
                    //一条告警都没有 就不需要往下走 这句话是必须加上的
                    return;
                }
                //4 基于数据库 都存在 对and进行告警
                for (int i = 0; i < andConfigs.size(); i++) {
                    AlarmEventConfigDto andConfig = andConfigs.get(0);
                    if (andConfig.getAlarmRuleIds() != null) {
                        List<Long> ruleIds = JacksonUtils.parseArray(andConfig.getAlarmRuleIds(), Long.class);
                        int j = 0;
                        for (j = 0; j < ruleIds.size(); j++) {
                            if (!dbCurrentAlarmRules.contains(ruleIds.get(j))) {
                                //数据库没有当前告警 则结束
                                break;
                            }
                        }
                        if (j >= ruleIds.size()) {
                            //都存在则告警
                            //开始生成事件记录 包括工单的保存 需要在同一事务上
                            AlarmEventRecordDto alarmEventRecordDto = new AlarmEventRecordDto();
                            alarmEventRecordDto.setTenantId(deviceDto.getTenantId());
                            alarmEventRecordDto.setVillageId(deviceDto.getVillageId());
                            alarmEventRecordDto.setBuildingId(deviceDto.getBuildingId());
                            alarmEventRecordDto.setDeviceCategoryId(deviceDto.getDeviceCategoryId());
                            alarmEventRecordDto.setDeviceTypeId(deviceDto.getDeviceTypeId());
                            alarmEventRecordDto.setDeviceId(deviceDto.getId());
                            alarmEventRecordDto.setImei(deviceDto.getImei());
                            alarmEventRecordDto.setEventConfigId(andConfig.getId());
                            alarmEventRecordDto.setName(andConfig.getName());
                            alarmEventRecordDto.setEventDesc(andConfig.getEventDesc());
                            alarmEventRecordDto.setStatus(AlarmConstants.ALARM_EVENT_RECORD_HANDLING);
                            alarmEventRecordDto.setEventTime(new Date());

                            alarmEventRecordDto.setDeviceDto(deviceDto);

                            andConfig.setLinkageUrl(sysConfigService.getConfigValueByKey(SysConfigKeyConstants.GATEWAY_INNER_BASE_URL) + SystemConstants.ApiPath.CMS_PATH + "/alarmLinkageCallback");

                            alarmEventRecordDto.setAlarmEventConfigDto(andConfig);

                            if (SystemConstants.YES.equals(andConfig.getIsAutoGenerateWorkOrder())) {
                                SysUserDto sysUserDto = sysUserService.selectCacheById(andConfig.getWorkOrderHandlerId());
                                if (sysUserDto != null) {
                                    andConfig.setWorkOrderHandlerUsername(sysUserDto.getUsername());
                                    andConfig.setWorkOrderHandlerMobile(sysUserDto.getMobile());
                                    andConfig.setWorkOrderHandlerEmail(sysUserDto.getEmail());
                                }
                            }

                            EventGenerateResponse response = alarmEventRecordService.generateEventRecord(alarmEventRecordDto);
                            if (response.isNeedPush()) {
                                pushMsg(alarmEventRecordDto);
                            }
                            if (response.isNeedLinkDevice()) {
                                linkDevice(alarmEventRecordDto);
                            }
                        }
                    }
                }
            }
        }

    }


    /**
     * 推送消息
     *
     * @param alarmEventRecordDto
     */
    private void pushMsg(AlarmEventRecordDto alarmEventRecordDto) {
        DATA_PROCESSING_THREAD_POOL.submit(() -> {
            AlarmEventConfigDto alarmEventConfigDto = alarmEventRecordDto.getAlarmEventConfigDto();
            if (StringUtils.isNotBlank(alarmEventConfigDto.getPushTypes())) {
                List<String> pushTypeList = JacksonUtils.parseArray(alarmEventConfigDto.getPushTypes(), String.class);
                if (pushTypeList == null || pushTypeList.size() <= 0) {
                    return;
                }
                //开始推送
                List<AlarmEventPushUserDto> alarmEventPushUserDtos = alarmEventPushUserService.selectCacheByAlarmEventConfigId(alarmEventConfigDto.getId());
                if (alarmEventPushUserDtos == null || alarmEventPushUserDtos.size() <= 0) {
                    return;
                }
                //工单上也有处理人去重
                Set<Long> pushSysUserIds = alarmEventPushUserDtos.stream().map(AlarmEventPushUserDto::getSysUserId).collect(Collectors.toSet());
                if (SystemConstants.YES.equals(alarmEventConfigDto.getIsAutoGenerateWorkOrder()) && alarmEventConfigDto.getWorkOrderHandlerId() != null) {
                    pushSysUserIds.add(alarmEventConfigDto.getWorkOrderHandlerId());
                }
                if (pushSysUserIds == null || pushSysUserIds.size() <= 0) {
                    return;
                }

                List<SysUserDto> sysUserDtoList = sysUserService.selectCacheListByBatchIds(new ArrayList<>(pushSysUserIds));
                if (sysUserDtoList == null || sysUserDtoList.size() <= 0) {
                    return;
                }
                //开始推送内容
                if (pushTypeList.contains(AlarmConstants.ALARM_EVENT_CONFIG_PUSH_TYPE_MSG)) {
                    //手机推送
                    for (SysUserDto sysUserDto : sysUserDtoList) {
                        smsBusiness.sendCommonMsg(sysUserDto.getTenantId(), sysUserDto.getMobile(),
                                alarmEventConfigDto.getName(), alarmEventConfigDto.getEventDesc());
                    }
                }


            }
        });
    }

    /**
     * 处理联动
     */
    private void linkDevice(AlarmEventRecordDto alarmEventRecordDto) {
        DeviceDto deviceDto = alarmEventRecordDto.getDeviceDto();
        AlarmEventConfigDto alarmEventConfigDto = alarmEventRecordDto.getAlarmEventConfigDto();

        DATA_PROCESSING_THREAD_POOL.submit(() -> {
            List<AlarmLinkageRuleDto> alarmLinkageRuleDtos = alarmLinkageRuleService.selectCacheByDeviceIdEventConfigId(deviceDto.getId(), alarmEventConfigDto.getId());
            if (CollectionUtil.isNotEmpty(alarmLinkageRuleDtos)) {
                for (AlarmLinkageRuleDto alarmLinkageRuleDto : alarmLinkageRuleDtos) {
                    HTTP_REST_UTILS.post(
                            alarmEventConfigDto.getLinkageUrl(),
                            alarmLinkageRuleDto.getLinkageCommand(),
                            RandomHeaderSignUtils.sign(RandomHeaderSignUtils.SECRET_KEY),
                            null);
                }
            }
        });
    }

    /**
     * 告警恢复(本方法不能异步)
     *
     * @param deviceCurrentAlarmDto
     */
    public void recoverCurrentAlarm(DeviceCurrentAlarmDto deviceCurrentAlarmDto, Byte handMethod) {

        //告警恢复 这句话不能异步
        deviceCurrentAlarmService.deleteById(deviceCurrentAlarmDto.getId());

        DATA_PROCESSING_THREAD_POOL.submit(() -> {
            mongoDeviceService.recoveryAlarmLog(deviceCurrentAlarmDto, handMethod);
        });

    }

    /**
     * 重置告警状态并且更新最后一次数据
     *
     * @param deviceDto
     * @param parsedData
     */
    public List<DeviceCurrentAlarmDto> updateAlarmStatusAndMergeLastData(DeviceDto deviceDto, Map<String, Object> parsedData) {
        //设置设备的告警状态
        List<DeviceCurrentAlarmDto> deviceCurrentAlarmDtos = deviceCurrentAlarmService.queryByDeviceId(deviceDto.getId());
        DeviceDto updateObj = new DeviceDto();
        updateObj.setId(deviceDto.getId());
        updateObj.setAlarmStatus(deviceCurrentAlarmDtos != null && deviceCurrentAlarmDtos.size() > 0 ? SystemConstants.YES : SystemConstants.NO);

        //最后一次数据更新
        Map<String, Object> lastData = new HashMap<>();
        if (StringUtils.isNotBlank(deviceDto.getLastData()) && JSONUtil.isJson(deviceDto.getLastData())) {
            lastData = JacksonUtils.parse(deviceDto.getLastData(), HashMap.class);
        }
        lastData.putAll(parsedData);
        updateObj.setLastData(JacksonUtils.toJsonString(lastData));

        deviceService.updateById(updateObj);

        return deviceCurrentAlarmDtos;
    }

    /**
     * 推送数据到mongodb
     *
     * @param deviceDto
     * @param originalData
     * @param parsedData
     */
    private void pushDataToMongoDB(DeviceDto deviceDto, String originalData, Map<String, Object> parsedData) {
        DATA_PROCESSING_THREAD_POOL.submit(() -> {
            MongoDeviceDataLogDto mongoDeviceDataLogDto = new MongoDeviceDataLogDto();
            mongoDeviceDataLogDto.setDeviceDto(deviceDto);
            mongoDeviceDataLogDto.setOriginalData(originalData);
            mongoDeviceDataLogDto.setParsedData(parsedData);
            mongoDeviceDataLogDto.setCreateTime(new Date());
            mongoDeviceService.saveReportData(mongoDeviceDataLogDto);
        });

    }


    /**
     * 处理告警后的返回值
     */
    @Data
    @AllArgsConstructor
    public static class HandleAlarmResp {
        /**
         * 告警或者恢复的规则列表(去除 "3 传入的字段无法判断是否满足该告警")
         */
        private List<HandAlarmRuleInfo> realAlarmOrRecoverList;
        /**
         * 数据库当前的告警 事件的处理需要用的到无需查询两次
         */
        private List<DeviceCurrentAlarmDto> deviceCurrentAlarms;
    }

    /**
     * 处理告警
     *
     * @param deviceDto
     * @param parsedData
     */
    private HandleAlarmResp handleAlarm(DeviceDto deviceDto, String originalData, Map<String, Object> parsedData) {

        if (SystemConstants.NO.equals(deviceDto.getAlarmSwitch())) {
            log.info("设备告警关闭,不处理告警");
            return null;
        }


        List<HandAlarmRuleInfo> handAlarmRuleInfos = alarmRuleService.handDeviceAlarm(deviceDto, parsedData);

        //过滤出非未知的告警规则
        List<HandAlarmRuleInfo> realAlarmOrRecoverList = handAlarmRuleInfos.stream().filter(v -> !AlarmConstants.ALARM_UNKNOWN.equals(v.getAlarmConformLevel()))
                .collect(Collectors.toList());

        //需要加锁处理防止设备上报两次
        Lock spinLock = RedisUtils.getSpinLock(DEVICE_ALARM_LOCK + deviceDto.getId());
        spinLock.lock();
        try {
            for (HandAlarmRuleInfo handAlarmRuleInfo : realAlarmOrRecoverList) {

                DeviceCurrentAlarmDto deviceCurrentAlarmDto = deviceCurrentAlarmService.queryByDeviceIdAndRuleId(deviceDto.getId(), handAlarmRuleInfo.getAlarmRuleDto().getId());

                if (AlarmConstants.ALARM_YES.equals(handAlarmRuleInfo.getAlarmConformLevel())) {
                    //发生告警
                    if (deviceCurrentAlarmDto == null) {
                        //当前告警只存入一条
                        deviceCurrentAlarmDto = new DeviceCurrentAlarmDto();
                        deviceCurrentAlarmDto.setImei(deviceDto.getImei());
                        deviceCurrentAlarmDto.setTenantId(deviceDto.getTenantId());
                        deviceCurrentAlarmDto.setVillageId(deviceDto.getVillageId());
                        deviceCurrentAlarmDto.setBuildingId(deviceDto.getBuildingId());
                        deviceCurrentAlarmDto.setDeviceId(deviceDto.getId());
                        deviceCurrentAlarmDto.setDeviceCategoryId(deviceDto.getDeviceCategoryId());
                        DeviceCategoryDto deviceCategory = deviceDto.getDeviceCategory();
                        if (deviceCategory != null) {
                            deviceCurrentAlarmDto.setDeviceCategory(deviceCategory);
                        }
                        deviceCurrentAlarmDto.setDeviceTypeId(deviceDto.getDeviceTypeId());
                        DeviceTypeDto deviceType = deviceDto.getDeviceType();
                        if (deviceType != null) {
                            deviceCurrentAlarmDto.setDeviceType(deviceType);
                        }
                        deviceCurrentAlarmDto.setRuleId(handAlarmRuleInfo.getAlarmRuleDto().getId());
                        deviceCurrentAlarmDto.setAlarmRule(handAlarmRuleInfo.getAlarmRuleDto());
                        deviceCurrentAlarmDto.setAlarmDetailJson(JacksonUtils.toJsonString(handAlarmRuleInfo.getAlarmRuleDto()));
                        deviceCurrentAlarmDto.setRecData(JacksonUtils.toJsonString(parsedData));
                        deviceCurrentAlarmDto.setAlarmTime(new Date());
                        Long id = deviceCurrentAlarmService.save(deviceCurrentAlarmDto);
                        deviceCurrentAlarmDto.setId(id);
                    }
                    MongoDeviceAlarmLogDto mongoDeviceAlarmLogDto = new MongoDeviceAlarmLogDto();
                    mongoDeviceAlarmLogDto.setDeviceDto(deviceDto);
                    mongoDeviceAlarmLogDto.setOriginalData(originalData);
                    mongoDeviceAlarmLogDto.setParsedData(parsedData);
                    if (deviceCurrentAlarmDto.getAlarmRule() == null) {
                        //填充方便查询
                        deviceCurrentAlarmDto.setAlarmRule(JacksonUtils.parse(deviceCurrentAlarmDto.getAlarmDetailJson(), AlarmRuleDto.class));
                    }
                    mongoDeviceAlarmLogDto.setDeviceCurrentAlarmDto(deviceCurrentAlarmDto);
                    mongoDeviceAlarmLogDto.setStartTime(new Date());
                    mongoDeviceAlarmLogDto.setRecoveryState(SystemConstants.ABNORMAL);
                    mongoDeviceService.saveDeviceAlarmLog(mongoDeviceAlarmLogDto);

                    webSocketComponent.sendMsgToCmsApi(
                            deviceDto.getVillageId(),
                            SendMsgType.DEVICE_ALARM.getMsgTypeFlag(),
                            SendMsgType.DEVICE_ALARM.getTitle(),
                            SendMsgType.DEVICE_ALARM.getContentFunc().apply(new String[]{deviceDto.getName(), DateUtil.now(), handAlarmRuleInfo.getAlarmRuleDto().getName()}),
                            null
                    );


                } else {
                    if (deviceCurrentAlarmDto != null) {
                        recoverCurrentAlarm(deviceCurrentAlarmDto, AlarmConstants.ALARM_AUTO_CLOSE_TYPE);
                    }
                }
            }
            //设置设备的告警状态
            List<DeviceCurrentAlarmDto> deviceCurrentAlarms = updateAlarmStatusAndMergeLastData(deviceDto, parsedData);

            return new HandleAlarmResp(realAlarmOrRecoverList, deviceCurrentAlarms);
        } catch (Exception e) {
            log.error("告警加锁失败", e);
        } finally {
            spinLock.unlock();
        }
        return null;
    }


}
